/*
*  对应后台文件服务：
*   svr/hh-kms-svc-v20.js
*
* */


    var kmsPeerOptions= {
                configuration: {
                    "iceServers": [
                        {
                            urls: "stun:223.68.161.139:3478"
                        },
                        {
                            urls: ["turn:223.68.161.139:3478"],
                            username: "kurento",
                            credential: "kurento"
                        }
                    ]
                },
                mediaConstraints: {
                    audio: true,
                    video: {width: {exact: 1280}, height: {exact: 720}}
                }
            };
    var kmsPeerTypes = {
        send: kurentoUtils.WebRtcPeer.WebRtcPeerSendonly,
        rec: kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly,
        sendRec: kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv
    };
    class ThhuView{
        constructor(viewId , hostId,   tag , video){
            var me = this;
            try{
                me.config.viewId = ThhuChannel.isNull(viewId)?ThhuChannel.newId('hhuView',''):viewId;
                var hostId = window.localStorage.getItem('hhView.hostId');
                me.config.hostId = ThhuChannel.isNull(hostId)?ThhuChannel.newId('hhuHostId',''):hostId;
                me.config.tag = ThhuChannel.isNull(tag)?{}:tag;
                me.objs.video = video;
            }
            catch (e) {
                console.log(e);
            }
        }
        config={
            viewId:"",
            hostId:"",
            tag:{},
            viewType: 0
        };
        objs ={
            channel: null ,
            peer: null,
            end:null,
            video: null
        };
        openView= function (viewType , hdFlag , pipe ,  onOpen) {
            var me = this;
            try{
                me.closeView(function () {
                    if( ThhuChannel.isNull( me.objs.video)){
                        me.objs.video = document.createElement('video');
                        me.objs.video.setAttribute('id', 'video_'+me.config.viewId);
                        me.objs.video.setAttribute('autoplay','true');
                    }
                    var factory = [kurentoUtils.WebRtcPeer.WebRtcPeerSendonly, kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly][viewType];
                    var mediaConstraints=[
                        {
                            audio: true,
                            video: {frameRate:10}
                        } ,
                        {
                            audio: true,
                            video: {width: {exact: 1280}, height: {exact: 720}}
                        }
                    ][hdFlag];
                    var opts = JSON.parse(JSON.stringify(kmsPeerOptions));
                    opts.mediaConstraints = mediaConstraints;
                    if( viewType==0 ){
                        opts.localVideo = me.objs.video;
                    }
                    else if( viewType==1 ){
                        opts.remoteVideo = me.objs.video;
                    }
                    var newPeer = factory(opts, function (erPeer) {
                        me.objs.peer = newPeer;
                        var newEnd = function() {
                            pipe.create("WebRtcEndpoint", function (erEnd, end) {
                                me.objs.end = end;
                                ThhuChannel.kmsBindPeerEnd(me.objs.peer, me.objs.end, function (erBind) {
                                    if (hdFlag) {
                                        ThhuChannel.kmsSetHDWebRtcEndpoint(me.objs.end, function () {
                                            hhls.callBack(onOpen);
                                        });
                                    } else {
                                        hhls.callBack(onOpen);
                                    }
                                })
                            })
                        }
                        if( viewType==0){
                            ThhuChannel.getDevices(function (devices) {
                                me.objs.peer.devices = devices;
                                newEnd();
                            })
                        }
                        else{
                            newEnd();
                        }
                    })


                })
            }
            catch (e) {
                console.log(e);
            }
        };
        closeView= function (onClose) {
            var me = this;
            try{
                var closeEnd = function (onCloseEnd) {
                    try{
                        if(  me.objs.end && me.objs.end!=null){
                            end.release(function () {
                                end = null;
                                onCloseEnd();
                            })
                        }
                        else{
                            onCloseEnd();
                        }
                    }
                    catch (er) {
                        console.log(er);
                    }
                }
                var closePeer = function () {
                    try{
                        if(  me.objs.peer && me.objs.peer!=null){
                            me.objs.peer.peerConnection.close();
                            me.objs.peer.destroy();
                            me.objs.peer = null;
                        }
                        onClose();
                    }
                    catch (er) {
                        console.log(er);
                    }
                }
                closeEnd(function () {
                    closePeer()
                })
            }
            catch (e) {
                console.log(e);
            }
        };
        getSrcInfo= function () {
            var me = this;
            var res={}
            try{
                res={
                    viewId:me.config.viewId,
                    hostId: me.config.hostId,
                    tag: me.config.tag ,
                    endKmsId : (me.objs.end &&me.objs.end!=null)?me.objs.end.id : "",

                }
            }
            catch (e) {
                console.log(e);
            }
            return res;
        }

    };
    class ThhuChannel{
        constructor(appId , clientId , channelId, channelInfo , pipeKmsId){
            var me = this;
            try{
                me.config.appId = appId;
                me.config.clientId = ThhuChannel.isNull(clientId)?ThhuChannel.newId('clientId',''): clientId;
                me.config.channelId = channelId;
                me.config.channelInfo = ThhuChannel.isNull(channelInfo)?{}:channelInfo;
                me.config.pipeKmsId  = pipeKmsId;

                me.config.mq.topics.channelTopic = ["hhuChannel","channel",me.config.channelId ].join('/');
                me.config.mq.topics.publisherTopic = ["hhuChannel","publisher",me.config.channelId, me.config.clientId ].join('/');
                me.config.mq.topics.willMsgTopic = ["hhuChannel","offline",me.config.channelId ].join('/');
            }
            catch (e) {
                console.log(e);
            }
        }
        config={
            appId:"",
            clientId:"",
            channelInfo:"",
            pipeKmsId:"",
            kms:{
                kurentUrl: "wss://wss.hhdata.cn:8433/kurento",
                kmsPeerOptions: {
                    configuration: {
                        "iceServers": [
                            {
                                urls: "stun:223.68.161.139:3478"
                            },
                            {
                                urls: ["turn:223.68.161.139:3478"],
                                username: "kurento",
                                credential: "kurento"
                            }
                        ]
                    },
                    mediaConstraints: {
                        audio: true,
                        video: {width: {exact: 1280}, height: {exact: 720}}
                    }
                },
                kmsPeerTypes: {
                    send: kurentoUtils.WebRtcPeer.WebRtcPeerSendonly,
                    rec: kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly,
                    sendRec: kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv
                } ,
            },
            mq:{
                host:"gmggf8g.mqtt.iot.bj.baidubce.com",
                port:443,
                uid:"gmggf8g/peer",
                pwd:"a52bwKg22dCAuQzB",
                topics:{
                    channelTopic : "",
                    publisherTopic :"",
                    willMsgTopic :""
                }
            }
        };
        objs ={
            kmsClient: null ,
            mqClient: null,
            pipe:null,

        };
        events={
            onRecMsg: function (topic , msg) {},
        };
        channelPublishers={};
        static isNull = function (data) {
            var res = (!data) || (data==null) || (data=="");
            return res;
        };
        static newId = function (header , split) {
            var res = [header , ( new Date()).getTime() , parseInt(1000*Math.random())].join(split);
            return res;
        };
        getKmsClient = function (callback) {
            var me = this;
            try{
                if( me.objs.kmsClient  && me.objs.kmsClient!=null){
                    hhls.callBack(callback,me.objs.kmsClient);
                }
                else{
                    kurentoClient(me.config.kms.kurentUrl, function (error, client) {
                        if (client) {
                            client.getServerManager(function (erSvr , svr) {
                                client.serverManager = svr;
                                me.objs.kmsClient = client;
                                hhls.callBack(callback,client);
                            })
                        }
                    });
                }
            }
            catch (e) {
                console.log(e);
            }
        };
        openChannel = function(onOpen){
            var me = this;
            try{
                var loadPipe = function (onLoad) {
                    var newPipe = function () {
                        me.getKmsClient(function (client) {
                            client.create("MediaPipeline", function (erNp, np) {
                                var key = ['hhuChannel', me.config.appId, me.config.channelId].join('-');
                                var value = JSON.stringify(me.config.channelInfo);
                                np.addTag(key, value, function (erTag) {
                                    me.objs.pipe = np;
                                    me.config.pipeKmsId = np.id;
                                    onLoad(np);
                                })
                            })
                        });

                    };
                    if ( ThhuChannel.isNull(me.config.pipeKmsId)  ){
                        newPipe();
                    }
                    else{
                        me.getKmsClient(function (client) {
                            client.getMediaobjectById(me.config.pipeKmsId, function (erFind , pipe) {
                                if( pipe){
                                    onLoad(pipe);
                                }
                                else{
                                    newPipe();
                                }
                            })
                        })
                    }
                }
                var connectMqServer = function () {
                    var onConnect= function () {
                        me.objs.mqClient.subscribe(me.config.mq.topics.channelTopic+"/#");
                        me.objs.mqClient.subscribe(me.config.mq.topics.publisherTopic+"/#");
                        me.objs.mqClient.subscribe(me.config.mq.topics.willMsgTopic+"/#");
                    }
                    var onDisConnect= function () {
                        console.log('disconnect.')
                    }
                    var onRecMsg = function (msgData) {
                        var msg = JSON.parse(msgData.MsgContent);
                        me.events.onRecMsg(msgData.Topic , msg );
                    };
                    var willMsg = {
                        msgId: "offline",
                        msgBody: {
                            clientId: me.config.clientId
                        }
                    };
                    me.objs.mqClient = createMqClient(
                        me.config.mq.host, me.config.mq.port,me.config.mq.uid, me.config.mq.pwd,
                        me.config.clientId, "" , 1, me.config.mq.topics.willMsgTopic ,willMsg,
                        onConnect , onDisConnect , onRecMsg
                    );
                    me.objs.mqClient.connect( me.objs.mqClient.connectionOptions);
                }
                loadPipe(function (pipe) {
                    me.objs.pipe = pipe;
                    connectMqServer();
                    hhls.callBack(onOpen);
                })
            }
            catch (e) {
                console.log(e);
            }
        };
        sendMsg = function(topic , msgId , msgBody){
            var me = this;
            try{
                if( !ThhuChannel.isNull(me.objs.mqClient) && me.objs.mqClient.isConnected()){
                    me.objs.mqClient.publish( topic, JSON.stringify({msgId:msgId,msgBody:msgBody}),0,false);
                    console.log('send hello', msgBody);
                }
            }
            catch (e) {
                console.log(e);
            }
        };
        static kmsBindPeerEnd = function (peer , endpoint , callback) {
            try{
                var setCandidateEvent = function (peer, endpoint) {
                    try {
                        if (peer && endpoint) {
                            endpoint.on('OnIceCandidate', function (event) {
                                var candidate = event.candidate;
                                peer.addIceCandidate(candidate);
                                console.log(candidate);
                                console.log('candidate w->p')
                            });
                            peer.on('icecandidate', function (candidate) {
                                var iceCandidate = kurentoClient.register.complexTypes.IceCandidate(candidate);
                                endpoint.addIceCandidate(iceCandidate);
                                console.log(iceCandidate,candidate);
                                console.log('candidate p->w')

                            });
                        }
                    } catch (e) {
                        ;
                    }
                }
                if (endpoint && peer) {
                    peer.generateOffer(function (errorPeerGenerateOffer, sdpOffer) {
                        if (errorPeerGenerateOffer && callback) {
                            callback(errorPeerGenerateOffer, null);
                        } else {
                            endpoint.processOffer(sdpOffer, function (errorSdpOffer, sdpAnswer) {
                                if (errorSdpOffer && callback) {
                                    console.log("process sdpOffer error.", errorSdpOffer)
                                    callback(errorSdpOffer, null);
                                } else {
                                    setCandidateEvent(peer, endpoint);
                                    peer.processAnswer(sdpAnswer);
                                    endpoint.gatherCandidates(function (errorGatherCandidates) {
                                        if (errorGatherCandidates && callback) {
                                            console.log('webRtcPoint gatherCandidates error.', errorGatherCandidates)
                                            callback(errorGatherCandidates, null);
                                        } else {
                                            peer.endpoint = endpoint;
                                            endpoint.peer = peer;
                                            setCandidateEvent(peer, endpoint);
                                            if (callback) {
                                                callback(null, {endpoint: endpoint, peer: peer});
                                            }
                                        }
                                    });
                                }
                            });
                        }
                    });
                } else {
                    if (callback) {
                        callback({error: "endPoint or peer is null."}, null);
                    }
                }

            }
            catch (e) {
                console.log(e);
            }
        };
        static kmsSetHDWebRtcEndpoint = function ( end, onSet ) {
            try{
                ThhuChannel.kmsSetWebRtcEndpointQuailty(end , 3000 , 1500, onSet);
            }
            catch (e) {
                console.log(e);
            }
        };
        static kmsSetSDWebRtcEndpoint = function ( end, onSet ) {
            try{
                ThhuChannel.kmsSetWebRtcEndpointQuailty(end , 1000 , 500, onSet);
            }
            catch (e) {
                console.log(e);
            }
        };
        static kmsSetWebRtcEndpointQuailty = function ( end, maxBandWidth, minBndWidth , onSet ) {
            try{
                end.setMaxVideoRecvBandwidth(maxBandWidth).then(()=>{
                    return end.setMaxVideoRecvBandwidth(maxBandWidth);
                }).then(()=>{
                    return end.setMaxVideoSendBandwidth(maxBandWidth);
                }).then(()=>{
                    return end.setMinVideoRecvBandwidth(minBndWidth);
                }).then(()=>{
                    return end.setMinVideoSendBandwidth(minBndWidth);
                }).then(()=>{
                    onSet();
                });
            }
            catch (e) {
                console.log(e);
            }
        };
        static getDevices = function (onGet) {
            try{
                var res ={};
                navigator.mediaDevices.enumerateDevices().then(function (devs) {
                    try {
                        for (var i = 0; i < devs.length; i++) {
                            var item = devs[i];
                            if (!res[item.kind]) {
                                res[item.kind] = []
                            }
                            res[item.kind].push(item);
                        }
                    }
                    catch (er) {
                        console.log(er)
                    }
                    hhls.callBack( onGet , res);
                }).catch(function () {
                    hhls.callBack( onGet , res);
                });
            }
            catch (e) {
                console.log(e);
            }
        };
        static acSetCamera = function ( peer ,  cameraDeviceId ,onSetCamera) {
            var me = this;
            try{
                if (window.rtcVideoStream) {
                    window.rtcVideoStream.getTracks().forEach(track => {
                        if( track.kind=="video") {
                            track.stop();
                        }
                    });
                }
                var constraints = {video: {deviceId: cameraDeviceId , height:{exact:720} , width:{exact:1280}}};
                var sender= null;
                navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
                    try {
                        window.rtcVideoStream = stream;
                        peer.localVideo.srcObject = stream;
                        let videoTrack = stream.getVideoTracks()[0];
                        sender = peer.peerConnection.getSenders().find(function (s) {
                            return s.track.kind == videoTrack.kind;
                        });
                        sender.replaceTrack(videoTrack);
                        hhls.callBack(onSetCamera);
                    }
                    catch (eSet) {
                        hhls.callBack( onSetCamera);
                    }
                }).catch(function () {
                    hhls.callBack(onSetCamera);
                });
            }
            catch (e) {
                console.log(e);
            }
        };
        static acSwitchCamera = function (peer) {
            var me = this;
            try{
                var ids =[
                    peer.devices.videoinput[0].deviceId ,
                    peer.devices.videoinput[peer.devices.videoinput.length-1].deviceId
                ];
                var cameraId = (
                    peer.cameraId  &&
                    peer.cameraId !=null &&
                    peer.cameraId.length>0 )?peer.cameraId : "";
                cameraId = cameraId == ids[1]?ids[0]:ids[1];
                ThhuChannel.acSetCamera(peer , cameraId , function () {
                    peer.cameraId = cameraId;
                })
            }
            catch (e) {
                console.log(e);
            }
        };
        static acToggleAudioMute = function (peer) {
            try{
                peer.peerConnection.audioEnabled = !peer.peerConnection.audioEnabled;
            }
            catch (e) {
                console.log(e);
            }
        };
        static acToggleVideoMute = function (peer) {
            try{
                peer.peerConnection.videoEnabled = !peer.peerConnection.videoEnabled;
            }
            catch (e) {
                console.log(e);
            }
        };
        static acTogglePlayVolume = function (peer) {
            try{
                peer.remoteVideo.volume = peer.remoteVideo.volume==0?1:0;
            }
            catch (e) {
                console.log(e);
            }
        };
        static acShareScreen = function (peer ,width , height) {
            try{
                var wWidth = width?width : $(window).width();
                var wHeight = height?height: $(window).height();
                var screenConstraints = {video: {width: {max:wWidth}, height: {max: wHeight}}, audio: true};
                var sender= null;
                if (navigator.mediaDevices.getDisplayMedia) {
                    navigator.mediaDevices.getDisplayMedia(screenConstraints).then(
                        function (stream) {
                            let videoTrack = stream.getVideoTracks()[0];
                            peer.localVideo.srcObject = stream;
                            sender = peer.peerConnection.getSenders().find(function (s) {
                                return s.track.kind == videoTrack.kind;
                            });
                            sender.track.stop();
                            sender.replaceTrack(videoTrack);
                        }
                    )
                }
            }
            catch (e) {
                console.log(e);
            }
        };
        static acFullScreen = function (peer) {
            var element = peer.remoteVideo;
            if (element.requestFullscreen) {
                element.requestFullscreen();
            } else if (element.msRequestFullscreen) {
                element.msRequestFullscreen();
            } else if (element.mozRequestFullScreen) {
                element.mozRequestFullScreen();
            } else if (element.webkitRequestFullscreen) {
                element.webkitRequestFullscreen();
            }
        };

    };
    class ThhWxLoginData{
        wxAppId="heHaiXieTong";
        code="";
        state="";
        sysId="";
        action="";
        accessToken="";
        accessTokenTime=0;
        refreshToken="";
        refreshTokenTime=0;
        openId="";
        userInfo={};
    };
    class ThhWxLogin{
        config = {
            acs:{
                acNotifyhhRoomPc:{
                    ac:'notify',
                    topic:'wxLogin/notify/hhRoom'
                },
                acNotifyhhRoomMo:{
                    ac:'redirect',
                    url:'https://wss.hhdata.cn'
                }
            },
            redirectWxUrl :"https://open.weixin.qq.com/connect/oauth2/authorize?appid=[wxAppId]&redirect_uri=https%3A%2F%2Fwx.hhdata.cn%2Fapps%2Fwss%2FwxBridge.htm&response_type=code&scope=snsapi_userinfo&state=[state]#wechat_redirect"
        };
        data = new ThhWxLoginData();
        loadData = function () {
            var me = this;
            try{
                var aData = new ThhWxLoginData();
                me.data.state = hhls.getUrlParamByDefault('state',"");
                me.data.code = hhls.getUrlParamByDefault('code',"");
                var localKey = "ThhWxLogin.state."+ me.data.state;
                var info = hhls.loadLocalObj(localKey);
                if( !info || info==null){
                    info = {};
                }

                var getValue = function (key  , defaultValue) {
                    var res = defaultValue;
                    var urlVal = hhls.getUrlParamByDefault(key, '');
                    if( urlVal==""){
                        if( info[key] ){
                            res = info[key];
                        }
                    }
                    else{
                        res = urlVal;
                    }
                    return res;
                }

                var setValue = function (key, defaultValue) {
                    var val = getValue(key,defaultValue);
                    me.data[key]= val;
                    //info[key] = val;
                }

                setValue("sysId",'');
                setValue("action",'');
                setValue("accessToken",'');
                setValue("accessTokenTime",0);
                setValue("refreshToken",'');
                setValue("refreshTokenTime",0);
                setValue("openId",'');

                me.data.callAction = me.config.acs[me.data.action];

                me.saveLocal();

            }
            catch (e) {
                console.log(e);
            }

        };
        getAccessTokenByCode = function (onGet) {
            var me = this;
            try{
                var ps = {
                    wxAppId: me.data.wxAppId ,
                    code : me.data.code
                };
                hhKmsClient.callApi("hhWxLoginGetAccessTokenByCode", ps, function (aRes) {
                    var tokenInfo = aRes.data;
                    if( tokenInfo&& tokenInfo!=null) {
                        var now = ( new Date()).getTime();
                        me.data.accessToken = tokenInfo.access_token;
                        me.data.refreshToken = tokenInfo.refresh_token;
                        me.data.openId = tokenInfo.openid;
                        me.data.accessTokenTime = now;
                        me.data.refreshTokenTime = now;
                        me.saveLocal();
                    }
                    onGet( );
                })
            }
            catch (e) {
                console.log(e);
            }
        };
        getAccessTokenByRefresh = function (onGet) {
            var me = this;
            try{
                var ps = {
                    wxAppId: me.data.wxAppId ,
                    refreshToken : me.data.refreshToken
                };
                hhKmsClient.callApi("hhWxLoginGetAccessTokenByRefresh", ps, function (aRes) {
                    var tokenInfo = aRes.data;
                    if( tokenInfo&& tokenInfo!=null) {
                        var now = ( new Date()).getTime();
                        me.data.accessToken = tokenInfo.access_token;
                        me.data.refreshToken = tokenInfo.refresh_token;
                        me.data.openId = tokenInfo.openid;
                        me.data.accessTokenTime = now;
                        me.saveLocal();
                    }
                    onGet( );
                })
            }
            catch (e) {
                console.log(e);
            }
        };
        getUserInfoByAccessToken = function (onGet) {
            var me = this;
            try{
                var ps = {
                    wxAppId: me.data.wxAppId ,
                    accessToken : me.data.accessToken ,
                    openId : me.data.openId
                };
                hhKmsClient.callApi("hhWxLoginGetUserInfoByAccessToken", ps, function (aRes) {
                    if( aRes.data) {
                        me.data.userInfo = aRes.data.userInfo;
                    }
                    else{
                        me.datas.userInfo={};
                    }
                    onGet();
                })
            }
            catch (e) {
                console.log(e);
            }
        };
        getRedirectUrl = function (onGet) {
            var me = this;
            try{
                var ps = {wxAppId: me.data.wxAppId , state : me.data.state};
                hhKmsClient.callApi("hhWxLoginGetRedirectUrl", ps, function (aRes) {
                    onGet( aRes.data);
                });
            }
            catch (e) {
                console.log(e);
            }
        };
        redirect2WxUrl = function ( ) {
            var me = this;
            try{
                var state = me.data.state;
                //var url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx29435f02de2545d8&redirect_uri=https%3A%2F%2Fwx.hhdata.cn%2Fapps%2Fwss%2FwxBridge.htm&response_type=code&scope=snsapi_userinfo&state="+state+"#wechat_redirect";
                var url = me.config.redirectWxUrl.replace("[wxAppId]",me.data.wxAppId).replace("[state]",me.data.state);
                hhls.goUrl(url);
            }
            catch (e) {
                console.log(e);
            }
        };
        saveLocal = function ( ) {
            var me = this;
            try{
                var info = {
                    sysId: me.data.sysId ,
                    action: me.data.action ,
                    accessToken: me.data.accessToken ,
                    accessTokenTime: me.data.accessTokenTime ,
                    refreshToken: me.data.refreshToken ,
                    refreshTokenTime: me.data.refreshTokenTime ,
                    openId: me.data.openId
                };
                var localKey = "ThhWxLogin.state."+ me.data.state;
                hhls.saveLocalObj(localKey, info);
            }
            catch (e) {
                console.log(e);
            }
        };
        apply = function (onApply) {
            var me = this;
            try{
                me.loadData();
                var now = ( new Date()).getTime();
                if( me.data.code ==""){
                    var refreshTimeoutFlag = ( now - me.data.refreshTokenTime ) > 28 * 24 * 3600 * 1000;
                    var accessTimeoutFlag = ( now - me.data.accessTokenTime ) > 6300 * 1000;
                    if( refreshTimeoutFlag){
                        me.getRedirectUrl(function (url) { var res ={
                            status:-1,
                                url:url
                            }
                            onApply(res);
                        })
                    }
                    else if( accessTimeoutFlag){
                        me.getAccessTokenByRefresh(function () {
                            me.getUserInfoByAccessToken(function () {
                                var res ={
                                    status:1,
                                    userInfo:me.data.userInfo
                                }
                                onApply(res);
                            })
                        })
                    }
                    else{
                        me.getUserInfoByAccessToken(function () {
                                var res ={
                                    status:1,
                                    userInfo:me.data.userInfo
                                }
                                onApply(res);
                        })
                    }
                }
                else{
                    me.getAccessTokenByCode(function () {
                        me.getUserInfoByAccessToken(function () {
                                var res ={
                                    status:1,
                                    userInfo:me.data.userInfo
                                }
                                onApply(res);
                        })
                    })
                }
            }
            catch (e) {
                console.log(e);
            }
        }
    };


    class THhRoom{
        constructor (roomId , roomInfo){
            var me = this;
            try{
                me.config.roomId = roomId;
                me.config.roomInfo = roomInfo;
                me.config.clientId = THhRoom.newId('cid',"");
                var hostKey = " hhRoom.HostKey";
                var hostId = window.localStorage.getItem(hostKey);
                if( THhRoom.isNull(hostId)){
                    hostId = THhRoom.newId('hhRoom_hostId_','_');
                    window.localStorage.setItem(hostKey , hostId);
                }
                me.config.hostId = hostId;
                me.config.mq.topics.roomTopic = "hhRoom/room/"+me.config.roomId.toString();
                me.config.mq.topics.clientTopic = "hhRoom/client/"+me.config.roomId.toString()+"/"+me.config.clientId;
                me.config.mq.topics.willMsgTopic = "hhRoom/willMsg/"+me.config.roomId.toString();
            }
            catch (e) {
                console.log(e);
            }
        }
        config={
            roomId:"",
            clientId:"",
            hostId:"",
            roomInfo:"",
            pipeKmsId:"",
            kms:{
                kurentUrl: "wss://wss.hhdata.cn:8433/kurento",
                kmsPeerOptions: {
                    configuration: {
                        "iceServers": [
                            {
                                urls: "stun:223.68.161.139:3478"
                            },
                            {
                                urls: ["turn:223.68.161.139:3478"],
                                username: "kurento",
                                credential: "kurento"
                            }
                        ]
                    },
                    mediaConstraints: {
                        audio: true,
                        video: {width: {exact: 1280}, height: {exact: 720}}
                    }
                },
                kmsPeerTypes: {
                    send: kurentoUtils.WebRtcPeer.WebRtcPeerSendonly,
                    rec: kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly,
                    sendRec: kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv
                } ,
            },
            mq:{
                host:"gmggf8g.mqtt.iot.bj.baidubce.com",
                port:443,
                uid:"gmggf8g/peer",
                pwd:"a52bwKg22dCAuQzB",
                topics:{
                    roomTopic : "",
                    clientTopic :"",
                    willMsgTopic :""
                }
            }
        };
        objs={
            mqClient : null ,
            kmsClient : null,
            pipe: null
        };
        getKmsClient = function (callback) {
            var me = this;
            try{
                if( me.objs.kmsClient  && me.objs.kmsClient!=null){
                    hhls.callBack(callback,me.objs.kmsClient);
                }
                else{
                    kurentoClient(me.config.kms.kurentUrl, function (error, client) {
                        if (client) {
                            client.getServerManager(function (erSvr , svr) {
                                client.serverManager = svr;
                                me.objs.kmsClient = client;
                                hhls.callBack(callback,client);
                            })
                        }
                    });
                }
            }
            catch (e) {
                console.log(e);
            }
        };
        loadRoomPipe = function (kmsId , callback) {
            var me = this;
            try{
                me.getKmsClient(function (client) {
                    var onOpenRoom = function (pipe, newPipeFlag) {
                        me.objs.pipe = pipe;
                        callback (pipe, newPipeFlag )
                    }
                    var newPipe = function(){
                        client.create("MediaPipeline", function (erPipe , pipe) {
                            if( pipe){
                                pipe.addTag("hhuRoomInfo", JSON.stringify(me.config.roomInfo), function (erTag) {
                                    onOpenRoom(pipe,1);
                                })
                            }
                        })
                    }
                    if( kmsId && kmsId!=null && kmsId.length>0) {
                        client.getMediaobjectById(kmsId, function (erFind, pipe) {
                            if (pipe && pipe != null) {
                                onOpenRoom(pipe, 0);
                            } else {
                                newPipe( );
                            }
                        })
                    }
                    else{
                        newPipe();
                    }
                })
            }
            catch (e) {
                console.log(e);
            }
        };
        openMqClient = function(  onMqOpen , onMqClose , onMqRecMsg){
            var me = this;
            try{
                var client= me.objs.mqClient;
                if( !client || client== null) {
                    var onConnect = function () {
                        client.subscribe(me.config.mq.topics.roomTopic+"/#");
                        client.subscribe(me.config.mq.topics.clientTopic+"/#");
                        client.subscribe(me.config.mq.topics.willMsgTopic+"/#");
                        THhRoom.cb(onMqOpen);
                    };
                    var onDisConnect = function () {
                        THhRoom.cb(onMqClose);
                    };
                    var onRecMsg = function (msgData) {
                        var msg = JSON.parse(msgData.MsgContent);
                        THhRoom.cb(onMqRecMsg, msg, msgData.topics);
                    };
                    var willTopic = me.config.mq.topics.willMsgTopic;
                    var willMsg = {
                        msgId:"offline" ,
                        msgBody:{
                            roomId: me.config.roomId,
                            roomInfo: me.config.roomInfo,
                            clientId: me.config.clientId
                        }
                    }
                    client = createMqClient(
                        me.config.mq.host,
                        me.config.mq.port,
                        me.config.mq.uid,
                        me.config.mq.pwd,
                        me.config.clientId,
                        "",
                        1, willTopic, willMsg,
                        onConnect, onDisConnect, onRecMsg
                    );
                    me.objs.mqClient = client;
                }
            }
            catch (e) {
                console.log(e);
            }
            return me.objs.mqClient;
        };
        sendMsg = function(topic ,  msgId , msgBody){
            var me = this;
            try{
                if( me.objs.mqClient && me.objs.mqClient !=null && me.objs.mqClient.isConnected()){
                    me.objs.mqClient.publish( topic , JSON.stringify({msgId:msgId, msgBody:msgBody}), 0 , false);
                }
            }
            catch (e) {
                console.log(e);
            }
        };
        sendMsg2Room = function( msgId , msgBody){
            var me = this;
            try{
                var topic = me.config.mq.topics.roomTopic ;
                me.sendMsg( topic , msgId , msgBody);
            }
            catch (e) {
                console.log(e);
            }
        };
        sendMsg2Client = function( targetClientId, msgId , msgBody){
            var me = this;
            try{
                var topic = "hhRoom/client/"+me.config.roomId.toString()+"/"+targetClientId ;
                me.sendMsg( topic , msgId , msgBody);
            }
            catch (e) {
                console.log(e);
            }
        };
        static isNull = function (data) {
            var res = (!data) || (data==null) || (data=="");
            return res;
        };
        static cb = function (callback,p0,p1,p2) {
            if( callback){
                try{
                    callback(p0,p1,p2);
                }
                catch (e) {
                    console.log(e)
                }
            }
        };
        static newId = function (header , split) {
            var res = [header , ( new Date()).getTime() , parseInt(1000*Math.random())].join(split);
            return res;
        };
        static createNewPushRecPeer = function (pipe , pId , localVideo , remoteVideo , tag , onCreate ) {
            try{
                if ( !pId || pId==null || pId=="" ){
                    pId = THhRoom.newId("pId","");
                }
                if( THhRoom.isNull(localVideo)){
                    localVideo = document.createElement('video');
                    localVideo.setAttribute('id', ['localVideo',pId].join('_'));
                    localVideo.setAttribute('autoplay','true');
                }
                if( THhRoom.isNull(remoteVideo)){
                    remoteVideo = document.createElement('video');
                    remoteVideo.setAttribute('id', ['remoteVideo',pId].join('_'));
                    remoteVideo.setAttribute('autoplay','true');
                }
                var opts = JSON.parse(JSON.stringify(kmsPeerOptions));
                opts.localVideo = localVideo;
                opts.remoteVideo = remoteVideo;
                var pusherMsgBody = {
                    pId: pId ,
                    tag: tag ,
                    endKmsId:""
                }
                var peer = kmsPeerTypes.sendRec(opts,function () {
                    peer.pId = pId;
                    peer.tag = tag;
                    pipe.create("WebRtcEndpoint", function (erEnd , end) {
                        THhRoom.kmsBindPeerEnd(peer , end , function () {
                            peer.free = function(onFree){
                                try{
                                    peer.peerconnection.close();
                                    peer.end.release(function () {
                                        peer.end = null;
                                        peer.destroy();
                                        peer = null;
                                        onFree();
                                    })
                                }
                                catch (erPeer) {
                                    console.log(erPeer);
                                }
                            };
                            end.setName("pId_PushRecPeer_"+pId, function (erName, name) {
                                pusherMsgBody.endKmsId = end.id;
                                peer.pusherMsgBody = pusherMsgBody;
                                THhRoom.kmsSetHDWebRtcEndpoint(end , function () {
                                    THhRoom.cb(onCreate, peer, end);
                                })
                            })
                        });
                    })
                })
            }
            catch (e) {
                console.log(e)
            }
        };
        static createNewRecPeer = function (pipe ,pId ,remoteVideo , tag , onCreate ) {
            try{
                if ( !pId || pId==null || pId=="" ){
                    pId = THhRoom.newId("pId","");
                }
                if( THhRoom.isNull(remoteVideo)){
                    remoteVideo = document.createElement('video');
                    remoteVideo.setAttribute('id', ['remoteVideo',pId].join('_'));
                    remoteVideo.setAttribute('autoplay','true');
                }
                var opts = JSON.parse(JSON.stringify(kmsPeerOptions));
                opts.remoteVideo = remoteVideo;
                var peer = kmsPeerTypes.rec(opts,function () {
                    peer.pId = pId;
                    peer.tag = tag;
                    pipe.create("WebRtcEndpoint", function (erEnd , end) {
                        THhRoom.kmsBindPeerEnd(peer , end , function () {
                            peer.free = function(onFree){
                                try{
                                    peer.peerConnection.close();
                                    peer.endpoint.release(function () {
                                        peer.endpoint = null;
                                        peer = null;
                                        onFree();
                                    })
                                }
                                catch (erPeer) {
                                    console.log(erPeer);
                                }
                            };
                            end.setName("pId_RecPeer_"+pId, function (erName, name) {
                                THhRoom.cb(onCreate, peer, end);
                            })
                        });
                    })
                })
            }
            catch (e) {
                console.log(e)
            }
        };
        static kmsBindPeerEnd = function (peer , endpoint , callback) {
            try{
                var setCandidateEvent = function (peer, endpoint) {
                    try {
                        if (peer && endpoint) {
                            endpoint.on('OnIceCandidate', function (event) {
                                var candidate = event.candidate;
                                peer.addIceCandidate(candidate);
                                console.log(candidate);
                                console.log('candidate w->p')
                            });
                            peer.on('icecandidate', function (candidate) {
                                var iceCandidate = kurentoClient.register.complexTypes.IceCandidate(candidate);
                                endpoint.addIceCandidate(iceCandidate);
                                console.log(iceCandidate,candidate);
                                console.log('candidate p->w')

                            });
                        }
                    } catch (e) {
                        ;
                    }
                }
                if (endpoint && peer) {
                    peer.generateOffer(function (errorPeerGenerateOffer, sdpOffer) {
                        if (errorPeerGenerateOffer && callback) {
                            callback(errorPeerGenerateOffer, null);
                        } else {
                            endpoint.processOffer(sdpOffer, function (errorSdpOffer, sdpAnswer) {
                                if (errorSdpOffer && callback) {
                                    console.log("process sdpOffer error.", errorSdpOffer)
                                    callback(errorSdpOffer, null);
                                } else {
                                    setCandidateEvent(peer, endpoint);
                                    peer.processAnswer(sdpAnswer);
                                    endpoint.gatherCandidates(function (errorGatherCandidates) {
                                        if (errorGatherCandidates && callback) {
                                            console.log('webRtcPoint gatherCandidates error.', errorGatherCandidates)
                                            callback(errorGatherCandidates, null);
                                        } else {
                                            peer.endpoint = endpoint;
                                            endpoint.peer = peer;
                                            setCandidateEvent(peer, endpoint);
                                            if (callback) {
                                                callback(null, {endpoint: endpoint, peer: peer});
                                            }
                                        }
                                    });
                                }
                            });
                        }
                    });
                } else {
                    if (callback) {
                        callback({error: "endPoint or peer is null."}, null);
                    }
                }

            }
            catch (e) {
                console.log(e);
            }
        };
        static kmsSetHDWebRtcEndpoint = function ( end, onSet ) {
            try{
                ThhuChannel.kmsSetWebRtcEndpointQuailty(end , 3000 , 1500, onSet);
            }
            catch (e) {
                console.log(e);
            }
        };
        static kmsSetSDWebRtcEndpoint = function ( end, onSet ) {
            try{
                ThhuChannel.kmsSetWebRtcEndpointQuailty(end , 1000 , 500, onSet);
            }
            catch (e) {
                console.log(e);
            }
        };
        static kmsSetWebRtcEndpointQuailty = function ( end, maxBandWidth, minBndWidth , onSet ) {
            try{
                end.setMaxVideoRecvBandwidth(maxBandWidth).then(()=>{
                    return end.setMaxVideoRecvBandwidth(maxBandWidth);
                }).then(()=>{
                    return end.setMaxVideoSendBandwidth(maxBandWidth);
                }).then(()=>{
                    return end.setMinVideoRecvBandwidth(minBndWidth);
                }).then(()=>{
                    return end.setMinVideoSendBandwidth(minBndWidth);
                }).then(()=>{
                    onSet();
                });
            }
            catch (e) {
                console.log(e);
            }
        };
        static getDevices = function (onGet) {
            try{
                var res ={};
                navigator.mediaDevices.enumerateDevices().then(function (devs) {
                    try {
                        for (var i = 0; i < devs.length; i++) {
                            var item = devs[i];
                            if (!res[item.kind]) {
                                res[item.kind] = []
                            }
                            res[item.kind].push(item);
                        }
                    }
                    catch (er) {
                        console.log(er)
                    }
                    hhls.callBack( onGet , res);
                }).catch(function () {
                    hhls.callBack( onGet , res);
                });
            }
            catch (e) {
                console.log(e);
            }
        };
        static acSetCamera = function ( peer ,  cameraDeviceId ,onSetCamera) {
            var me = this;
            try{
                if (window.rtcVideoStream) {
                    window.rtcVideoStream.getTracks().forEach(track => {
                        if( track.kind=="video") {
                            track.stop();
                        }
                    });
                }
                var constraints = {video: {deviceId: cameraDeviceId , height:{exact:720} , width:{exact:1280}}};
                var sender= null;
                navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
                    try {
                        window.rtcVideoStream = stream;
                        peer.localVideo.srcObject = stream;
                        let videoTrack = stream.getVideoTracks()[0];
                        sender = peer.peerConnection.getSenders().find(function (s) {
                            return s.track.kind == videoTrack.kind;
                        });
                        sender.replaceTrack(videoTrack);
                        hhls.callBack(onSetCamera);
                    }
                    catch (eSet) {
                        hhls.callBack( onSetCamera);
                    }
                }).catch(function () {
                    hhls.callBack(onSetCamera);
                });
            }
            catch (e) {
                console.log(e);
            }
        };
        static acSwitchCamera = function (peer) {
            var me = this;
            try{
                var ids =[
                    peer.devices.videoinput[0].deviceId ,
                    peer.devices.videoinput[peer.devices.videoinput.length-1].deviceId
                ];
                var cameraId = (
                    peer.cameraId  &&
                    peer.cameraId !=null &&
                    peer.cameraId.length>0 )?peer.cameraId : "";
                cameraId = cameraId == ids[1]?ids[0]:ids[1];
                ThhuChannel.acSetCamera(peer , cameraId , function () {
                    peer.cameraId = cameraId;
                })
            }
            catch (e) {
                console.log(e);
            }
        };
        static acToggleAudioMute = function (peer) {
            var res = false;
            try{
                var tracks = $.grep(peer.localVideo.srcObject.getTracks(), function (track) {
                    return track.kind === 'audio';
                });
                if(tracks.length>0){
                    var track = tracks[0];
                    track.enabled = !track.enabled;
                    res = track;
                }
//                peer.peerConnection.audioEnabled = !peer.peerConnection.audioEnabled;
            }
            catch (e) {
                console.log(e);
            }
            return res;
        };
        static acToggleVideoMute = function (peer) {
            try{
                peer.peerConnection.videoEnabled = !peer.peerConnection.videoEnabled;
            }
            catch (e) {
                console.log(e);
            }
        };
        static acTogglePlayVolume = function (peer) {
            try{
                peer.remoteVideo.volume = peer.remoteVideo.volume==0?1:0;
            }
            catch (e) {
                console.log(e);
            }
        };
        static acShareScreen = function (peer ,width , height) {
            try{
                var wWidth = width?width : $(window).width();
                var wHeight = height?height: $(window).height();
                var screenConstraints = {video: {width: {max:wWidth}, height: {max: wHeight}}, audio: true};
                var sender= null;
                if (navigator.mediaDevices.getDisplayMedia) {
                    navigator.mediaDevices.getDisplayMedia(screenConstraints).then(
                        function (stream) {
                            let videoTrack = stream.getVideoTracks()[0];
                            peer.localVideo.srcObject = stream;
                            sender = peer.peerConnection.getSenders().find(function (s) {
                                return s.track.kind == videoTrack.kind;
                            });
                            sender.track.stop();
                            sender.replaceTrack(videoTrack);
                        }
                    )
                }
            }
            catch (e) {
                console.log(e);
            }
        };
        static acFullScreen = function (peer) {
            var element = peer.remoteVideo;
            if (element.requestFullscreen) {
                element.requestFullscreen();
            } else if (element.msRequestFullscreen) {
                element.msRequestFullscreen();
            } else if (element.mozRequestFullScreen) {
                element.mozRequestFullScreen();
            } else if (element.webkitRequestFullscreen) {
                element.webkitRequestFullscreen();
            }
        };
    }
    var hhKmsClient ={
        config:{
            appid:"hhroom",
            apiUrl:"https://wss.hhdata.cn:20024/hhapi",
            clientId:ThhuChannel.newId('clientId')
        },
        callApi: function (ac , ps , callback) {
            var me = hhKmsClient;
            try{
                var aUrl = me.config.apiUrl;
                aUrl += "/"+ac;
                aUrl += aUrl.indexOf("?")>0?"&":"?";
                aUrl += "rt="+(new Date()).getTime().toString()+"."+Math.random().toString();
                $.ajax({
                    url:aUrl ,
                    data:JSON.stringify(ps) ,
                    contentType: "application/json; charset=utf-8", //必须有
                    dataType: "json", //表示返回值类型，不必须
                    type:"post",
                    success: function (res) {
                        console.log(res);
                        hhls.callBack(callback , res);
                    },
                    error: function (e0,e1) {
                        console.log(e0, e1);
                        hhls.callBack(callback , e0 , e1);
                    }
                })
            }
            catch (e) {
                console.log(e);
            }
        },
        getSvrTime: function ( callback) {
            var me = hhKmsClient;
            try{
                me.callApi('getSvrTime', {}, function (res) {
                    callback(res.data);
                })
            }
            catch (e) {
                console.log(e);
            }
        },
        wxCreateLoginQr: function(divId){
            var me = hhKmsClient;
            url = "https://wss.hhdata.cn:20024/apps/hhroom/wxlogin.html?sysId="+me.config.appid+"&clientId="+me.config.clientId;
            var qrcode = new QRCode(document.getElementById(divId), {
                text: url,
                width: 280,
                height: 280,
                colorDark : "#000000",
                colorLight : "#ffffff",
                correctLevel : QRCode.CorrectLevel.H
            });
        },
        wxGetAccessTokenUserInfo: function (ak ,callback) {
            var me = hhKmsClient;
            try{
                var localKey = "wxLogin."+ ak;
                var localInfo = hhls.loadLocalObj(localKey);
                localInfo = localInfo == null ? {} :  localInfo;
                var ps = {
                    ak: ak,
                    code:code ,
                    tag : tag ,
                    openId:localInfo['openId']?localInfo['openId']:"" ,
                    accessToken :localInfo['accessToken']?localInfo['accessToken']:"",
                    accessTime:localInfo['accessTime']?localInfo['accessTime']:0,
                    refreshToken:localInfo['refreshToken']?localInfo['refreshToken']:"",
                    refreshTime:localInfo['refreshTime']?localInfo['refreshTime']:0,
                };
                me.callApi("wxLogin" , ps , function (res) {
                    if( res.data && res.data.status==1){
                        var info = res.data.data;
                        hhls.saveLocalObj(localKey , info);
                    }
                    hhls.callBack(callback , res);
                })
            }
            catch (e) {
                console.log(e);
            }
        },
        dbQuery: function (appId , key , queryPs , callback) {
            var me = hhKmsClient;
            try{
                var ps = {
                    appId: appId ,
                    key: key ,
                    ps:JSON.stringify(queryPs)
                }
                me.callApi("dbQuery" , ps , function (res) {
                    hhls.callBack(callback , res);
                })
            }
            catch (e) {
                console.log(e);
            }
        }
    };